/**
 * 文件扫描模块
 * 用于查找和读取桌面应用的cookie文件
 */

const fs = require('fs');
const path = require('path');
const os = require('os');
const glob = require('glob');
const plist = require('plist');
const xml2js = require('xml2js');
const { promisify } = require('util');
const readFileAsync = promisify(fs.readFile);
const globAsync = promisify(glob);

// Cookie文件的常见名称和模式
const COOKIE_FILE_PATTERNS = [
  'Cookies',
  'cookies.sqlite',
  'cookies.db',
  'cookies.dat',
  'cookie*',
  'session*',
  'localStorage*',
  'storage.json',
  'data.json',
  'webdata*',
  'user.config',
  'user*.config',
  'setting*.json',
  'config*.json',
  '*.cookies',
  'Preferences',
  'Login Data',
  'Web Data',
  'settings.dat',
  'UserPrefs.xml',
  'State.xml',
  'settings.ini',
  'Settings.dat',
  '*.plist'
];

/**
 * 查找所有可能的cookie文件
 * @param {string} userDataDir - 用户数据目录
 * @param {string} appName - 应用名称
 * @returns {Promise<Array<string>>} - cookie文件路径数组
 */
async function findCookieFiles(userDataDir, appName) {
  const cookieFiles = [];
  
  if (!userDataDir || !fs.existsSync(userDataDir)) {
    return cookieFiles;
  }
  
  try {
    // 1. 常见的cookie文件路径
    const commonCookiePaths = [
      // Electron应用常见路径
      path.join(userDataDir, 'Cookies'),
      path.join(userDataDir, 'Default', 'Cookies'),
      path.join(userDataDir, 'Partitions', 'default', 'Cookies'),
      path.join(userDataDir, 'IndexedDB'),
      path.join(userDataDir, 'Local Storage'),
      // 其他桌面应用常见路径
      path.join(userDataDir, 'cookies.sqlite'),
      path.join(userDataDir, 'Cookies.dat'),
      path.join(userDataDir, 'cookies.dat'),
      path.join(userDataDir, 'Web Data'),
      path.join(userDataDir, 'Login Data'),
      path.join(userDataDir, 'settings.dat'),
      path.join(userDataDir, 'Settings'),
      path.join(userDataDir, 'Preferences'),
      // Windows常见配置文件位置
      path.join(userDataDir, 'user.config'),
      path.join(userDataDir, 'User.config')
    ];
    
    // 检查常见路径
    for (const cookiePath of commonCookiePaths) {
      if (fs.existsSync(cookiePath)) {
        cookieFiles.push(cookiePath);
      }
    }
    
    // 2. 特定平台的cookie文件路径
    const platform = os.platform();
    
    if (platform === 'darwin') {
      const macCookies = await findMacOSCookies(userDataDir, appName);
      cookieFiles.push(...macCookies);
    } else if (platform === 'win32') {
      const winCookies = await findWindowsCookies(userDataDir, appName);
      cookieFiles.push(...winCookies);
    }
    
    // 3. 递归查找匹配的文件名
    const appNameClean = appName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
    
    // 检查子目录
    const subdirs = await globAsync(`${userDataDir}/*`, { dot: true });
    
    for (const subdir of subdirs) {
      try {
        if (fs.statSync(subdir).isDirectory()) {
          const files = await recursivelyFindCookieFiles(subdir, 2);
          cookieFiles.push(...files);
        }
      } catch (err) {
        // 忽略权限错误等
        continue;
      }
    }
    
    // 4. 去重
    return [...new Set(cookieFiles)];
  } catch (err) {
    console.error(`找不到cookie文件: ${err.message}`);
    return cookieFiles;
  }
}

/**
 * 查找macOS系统上的cookie文件
 * @param {string} userDataDir - 用户数据目录
 * @param {string} appName - 应用名称
 * @returns {Promise<Array<string>>} - cookie文件路径数组
 */
async function findMacOSCookies(userDataDir, appName) {
  const cookieFiles = [];
  const home = process.env.HOME || `/Users/${process.env.USER}`;
  const appNameClean = appName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
  
  // macOS常见的cookie存储位置
  const macCookiePaths = [
    // 系统cookie存储
    path.join(home, 'Library/Cookies/Cookies.binarycookies'),
    // 应用容器内的cookies
    path.join(home, 'Library/Containers', appNameClean, 'Data/Library/Cookies'),
    path.join(home, 'Library/Containers', `com.${appNameClean}`, 'Data/Library/Cookies'),
    path.join(home, 'Library/Containers', appNameClean, 'Data/Library/Cookies/Cookies.binarycookies'),
    // Group Container中的cookies
    path.join(home, 'Library/Group Containers', appNameClean, 'Library/Cookies'),
    // 其他可能的位置
    path.join(home, 'Library/Application Support', appNameClean, 'Cookies'),
    path.join(home, 'Library/Caches', appNameClean),
    // plist文件
    path.join(home, 'Library/Preferences', `com.${appNameClean}.plist`),
    path.join(home, 'Library/Preferences', `${appNameClean}.plist`)
  ];
  
  for (const cookiePath of macCookiePaths) {
    if (fs.existsSync(cookiePath)) {
      cookieFiles.push(cookiePath);
    }
  }
  
  return cookieFiles;
}

/**
 * 查找Windows系统上的cookie文件
 * @param {string} userDataDir - 用户数据目录
 * @param {string} appName - 应用名称
 * @returns {Promise<Array<string>>} - cookie文件路径数组
 */
async function findWindowsCookies(userDataDir, appName) {
  const cookieFiles = [];
  const appNameClean = appName.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
  
  // C#应用配置文件位置
  const appData = process.env.APPDATA || `${process.env.USERPROFILE}\\AppData\\Roaming`;
  const localAppData = process.env.LOCALAPPDATA || `${process.env.USERPROFILE}\\AppData\\Local`;
  
  // Windows常见的cookie/配置存储位置
  const winCookiePaths = [
    // C#应用常用配置
    path.join(appData, `${appNameClean}`, 'user.config'),
    path.join(appData, `${appNameClean}_StrongName`, 'user.config'),
    path.join(localAppData, 'Packages', `${appNameClean}_StrongName`, 'Settings'),
    // C++/QT应用常用配置
    path.join(localAppData, appNameClean, 'Settings.dat'),
    path.join(localAppData, 'Temp', appNameClean, 'cookies.dat'),
    path.join(appData, 'QtProject', appNameClean, 'QWebEngineCookies'),
    // 其他可能的位置
    path.join(process.env.USERPROFILE || '', 'Documents', appNameClean, 'Settings.xml'),
    path.join(process.env.USERPROFILE || '', 'Documents', appNameClean, 'config.json')
  ];
  
  for (const cookiePath of winCookiePaths) {
    if (fs.existsSync(cookiePath)) {
      cookieFiles.push(cookiePath);
    }
  }
  
  return cookieFiles;
}

/**
 * 递归查找cookie相关文件
 * @param {string} directory - 要扫描的目录
 * @param {number} depth - 递归深度
 * @returns {Promise<Array<string>>} - 找到的文件路径数组
 */
async function recursivelyFindCookieFiles(directory, depth) {
  if (depth <= 0) return [];
  
  const results = [];
  
  try {
    // 匹配可能的cookie文件名
    for (const pattern of COOKIE_FILE_PATTERNS) {
      const matches = await globAsync(path.join(directory, pattern), { dot: true, nodir: true });
      results.push(...matches);
    }
    
    // 查找可能包含cookie关键词的文件
    const files = await globAsync(path.join(directory, '*'), { dot: true, nodir: true });
    
    for (const file of files) {
      const fileName = path.basename(file).toLowerCase();
      
      // 检查文件名是否包含cookie相关关键词
      if (fileName.includes('cookie') || 
          fileName.includes('session') || 
          fileName.includes('auth') || 
          fileName.includes('token') || 
          fileName.includes('login') || 
          fileName.includes('webdata') || 
          fileName.includes('setting') || 
          fileName.includes('config') || 
          fileName.includes('preference')) {
        results.push(file);
      }
    }
    
    // 递归查找子目录
    const subdirs = await globAsync(path.join(directory, '*'), { dot: true });
    
    for (const subdir of subdirs) {
      try {
        if (fs.statSync(subdir).isDirectory()) {
          const subResults = await recursivelyFindCookieFiles(subdir, depth - 1);
          results.push(...subResults);
        }
      } catch (err) {
        // 忽略权限错误等
        continue;
      }
    }
  } catch (err) {
    console.error(`递归查找cookie文件出错: ${err.message}`);
  }
  
  return [...new Set(results)];
}

/**
 * 读取cookie文件内容
 * @param {string} cookieFilePath - cookie文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function readCookieFile(cookieFilePath) {
  if (!fs.existsSync(cookieFilePath)) {
    return [];
  }
  
  const ext = path.extname(cookieFilePath).toLowerCase();
  const fileName = path.basename(cookieFilePath).toLowerCase();
  
  try {
    // 根据文件类型选择不同的读取方式
    if (ext === '.sqlite' || fileName.includes('cookie') && !ext) {
      // SQLite数据库，尝试使用better-sqlite3读取
      return await readSqliteCookies(cookieFilePath);
    } else if (ext === '.json' || fileName.includes('setting') || fileName.includes('config') && ext === '.json') {
      // JSON文件
      return await readJsonCookies(cookieFilePath);
    } else if (ext === '.xml' || ext === '.config') {
      // XML文件
      return await readXmlCookies(cookieFilePath);
    } else if (ext === '.plist') {
      // PLIST文件
      return await readPlistCookies(cookieFilePath);
    } else if (fileName === 'cookies.binarycookies' || fileName.includes('binarycookie')) {
      // macOS二进制cookie文件
      return await readBinaryCookies(cookieFilePath);
    } else if (ext === '.dat' || ext === '.bin' || !ext) {
      // 二进制或未知格式，尝试二进制分析
      return await extractBinaryCookies(cookieFilePath);
    } else {
      // 默认尝试以文本方式读取
      return await readTextCookies(cookieFilePath);
    }
  } catch (err) {
    console.error(`读取cookie文件出错 (${cookieFilePath}): ${err.message}`);
    return [];
  }
}

/**
 * 读取SQLite格式的cookie文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function readSqliteCookies(filePath) {
  try {
    // 尝试动态导入better-sqlite3
    const Database = require('better-sqlite3');
    const db = new Database(filePath, { readonly: true });
    
    // 尝试从不同表中读取cookie
    const tables = ['cookies', 'cookie', 'moz_cookies', 'firefox_cookies'];
    
    for (const table of tables) {
      try {
        const rows = db.prepare(`SELECT * FROM ${table}`).all();
        
        if (rows && rows.length > 0) {
          db.close();
          
          // 转换为标准格式
          return rows.map(row => {
            return {
              name: row.name || row.cookie_name,
              value: row.value || row.cookie_value,
              domain: row.host_key || row.host || row.domain,
              path: row.path || '/',
              expires: row.expires_utc || row.expiry || row.expires || 0,
              secure: Boolean(row.is_secure || row.secure),
              httpOnly: Boolean(row.is_httponly || row.httponly),
              sameSite: row.samesite || 'Lax'
            };
          });
        }
      } catch (err) {
        // 忽略表不存在等错误
        continue;
      }
    }
    
    db.close();
    return [];
  } catch (err) {
    console.error(`读取SQLite cookie文件出错: ${err.message}`);
    return [];
  }
}

/**
 * 读取JSON格式的cookie文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function readJsonCookies(filePath) {
  try {
    const data = await readFileAsync(filePath, 'utf8');
    const jsonData = JSON.parse(data);
    const cookies = [];
    
    // 尝试从不同JSON结构中提取cookie
    if (Array.isArray(jsonData)) {
      // 直接的cookie数组
      for (const item of jsonData) {
        if (item.name && item.value) {
          cookies.push({
            name: item.name,
            value: item.value,
            domain: item.domain || item.host || '',
            path: item.path || '/',
            expires: item.expires || item.expirationDate || 0,
            secure: Boolean(item.secure),
            httpOnly: Boolean(item.httpOnly),
            sameSite: item.sameSite || 'Lax'
          });
        }
      }
    } else {
      // 嵌套结构
      for (const key in jsonData) {
        // 检查常见的cookie容器字段
        const possibleContainers = [
          jsonData[key],
          jsonData.cookies,
          jsonData.cookie,
          jsonData.authTokens,
          jsonData.tokens,
          jsonData.credentials,
          jsonData.session,
          jsonData.data
        ];
        
        for (const container of possibleContainers) {
          if (!container) continue;
          
          if (Array.isArray(container)) {
            // 处理数组
            for (const item of container) {
              if (item && (item.name || typeof item === 'string')) {
                cookies.push(extractCookieFromObject(item, key));
              }
            }
          } else if (typeof container === 'object') {
            // 处理对象
            for (const ckey in container) {
              if (isValidCookieName(ckey)) {
                cookies.push({
                  name: ckey,
                  value: container[ckey],
                  domain: '',
                  path: '/'
                });
              } else if (typeof container[ckey] === 'object' && container[ckey] !== null) {
                // 可能是嵌套的cookie或token对象
                cookies.push(extractCookieFromObject(container[ckey], ckey));
              }
            }
          }
        }
      }
    }
    
    return cookies;
  } catch (err) {
    console.error(`读取JSON cookie文件出错: ${err.message}`);
    return [];
  }
}

/**
 * 读取XML格式的cookie文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function readXmlCookies(filePath) {
  try {
    const data = await readFileAsync(filePath, 'utf8');
    const parser = new xml2js.Parser({ explicitArray: false });
    const result = await parser.parseStringPromise(data);
    
    const cookies = [];
    
    // 处理.NET配置文件格式
    if (result.configuration && result.configuration.userSettings) {
      const settings = result.configuration.userSettings;
      
      // 遍历所有设置组
      for (const groupName in settings) {
        const group = settings[groupName];
        
        if (group.setting) {
          const settingList = Array.isArray(group.setting) ? group.setting : [group.setting];
          
          for (const setting of settingList) {
            // 检查设置名是否可能是cookie相关
            if (setting && setting.$.name && isValidCookieName(setting.$.name)) {
              cookies.push({
                name: setting.$.name,
                value: setting.value || '',
                domain: '',
                path: '/'
              });
            }
          }
        }
      }
    }
    
    // 处理可能的其他XML格式
    if (result.cookies && result.cookies.cookie) {
      const cookieList = Array.isArray(result.cookies.cookie) ? result.cookies.cookie : [result.cookies.cookie];
      
      for (const cookie of cookieList) {
        cookies.push({
          name: cookie.name || cookie.$.name,
          value: cookie.value || cookie.$.value,
          domain: cookie.domain || cookie.$.domain || '',
          path: cookie.path || cookie.$.path || '/',
          expires: cookie.expires || cookie.$.expires || 0,
          secure: Boolean(cookie.secure || cookie.$.secure),
          httpOnly: Boolean(cookie.httpOnly || cookie.$.httpOnly)
        });
      }
    }
    
    return cookies;
  } catch (err) {
    console.error(`读取XML cookie文件出错: ${err.message}`);
    return [];
  }
}

/**
 * 读取plist格式的cookie文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function readPlistCookies(filePath) {
  try {
    const data = await readFileAsync(filePath, 'utf8');
    const plistData = plist.parse(data);
    const cookies = [];
    
    // 处理可能的cookie数据结构
    for (const key in plistData) {
      // 检查是否是cookie容器
      if (key.includes('Cookie') || key.includes('Session') || key.includes('Auth') || key.includes('Token')) {
        if (Array.isArray(plistData[key])) {
          // 数组格式
          for (const item of plistData[key]) {
            if (item.Name && item.Value) {
              cookies.push({
                name: item.Name,
                value: item.Value,
                domain: item.Domain || '',
                path: item.Path || '/',
                expires: item.Expires || 0,
                secure: Boolean(item.Secure),
                httpOnly: Boolean(item.HttpOnly)
              });
            }
          }
        } else if (typeof plistData[key] === 'object') {
          // 对象格式
          for (const ckey in plistData[key]) {
            if (isValidCookieName(ckey)) {
              cookies.push({
                name: ckey,
                value: plistData[key][ckey],
                domain: '',
                path: '/'
              });
            }
          }
        } else if (typeof plistData[key] === 'string' && isValidCookieName(key)) {
          // 直接键值形式
          cookies.push({
            name: key,
            value: plistData[key],
            domain: '',
            path: '/'
          });
        }
      }
    }
    
    return cookies;
  } catch (err) {
    console.error(`读取plist cookie文件出错: ${err.message}`);
    return [];
  }
}

/**
 * 读取macOS二进制Cookie文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function readBinaryCookies(filePath) {
  try {
    // 由于二进制格式复杂，这里简单提取文本字符串
    return await extractBinaryCookies(filePath);
  } catch (err) {
    console.error(`读取二进制cookie文件出错: ${err.message}`);
    return [];
  }
}

/**
 * 提取二进制文件中的可能cookie数据
 * @param {string} filePath - 文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function extractBinaryCookies(filePath) {
  try {
    const data = await readFileAsync(filePath);
    
    // 从二进制数据中提取可能的cookie字符串
    const strings = extractStringsFromBinary(data);
    
    // 分析提取出的字符串，尝试构造cookie对象
    const cookies = [];
    
    // 尝试匹配cookie格式
    for (let i = 0; i < strings.length; i++) {
      const str = strings[i];
      
      // 检查是否看起来像cookie名称
      if (isValidCookieName(str) && i + 1 < strings.length) {
        const name = str;
        const value = strings[i + 1];
        
        // 构造cookie对象
        cookies.push({
          name: name,
          value: value,
          domain: '',
          path: '/'
        });
        
        // 跳过已处理的值
        i++;
      }
    }
    
    return cookies;
  } catch (err) {
    console.error(`从二进制提取cookie出错: ${err.message}`);
    return [];
  }
}

/**
 * 以文本方式读取cookie文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<Array<Object>>} - cookie对象数组
 */
async function readTextCookies(filePath) {
  try {
    const data = await readFileAsync(filePath, 'utf8');
    const cookies = [];
    
    // 尝试多种常见cookie格式匹配
    
    // 1. 常见的Set-Cookie格式
    const setCookieRegex = /([^=]+)=([^;]+);?\s*(?:expires=([^;]+))?;?\s*(?:domain=([^;]+))?;?\s*(?:path=([^;]+))?/g;
    let match;
    
    while ((match = setCookieRegex.exec(data)) !== null) {
      cookies.push({
        name: match[1].trim(),
        value: match[2],
        domain: match[4] || '',
        path: match[5] || '/',
        expires: match[3] ? new Date(match[3]).getTime() : 0
      });
    }
    
    // 2. 简单的名称=值格式
    const simpleRegex = /^\s*([^=\s]+)\s*=\s*(.+?)\s*$/gm;
    while ((match = simpleRegex.exec(data)) !== null) {
      // 避免与上面的正则匹配重复
      if (!cookies.some(c => c.name === match[1].trim())) {
        if (isValidCookieName(match[1].trim())) {
          cookies.push({
            name: match[1].trim(),
            value: match[2],
            domain: '',
            path: '/'
          });
        }
      }
    }
    
    return cookies;
  } catch (err) {
    console.error(`以文本方式读取cookie文件出错: ${err.message}`);
    return [];
  }
}

/**
 * 从二进制数据中提取字符串
 * @param {Buffer} buffer - 二进制数据
 * @returns {Array<string>} - 提取的字符串数组
 */
function extractStringsFromBinary(buffer) {
  const strings = [];
  let currentString = '';
  
  for (let i = 0; i < buffer.length; i++) {
    const byte = buffer[i];
    
    // 可打印ASCII字符范围 (32-126)
    if (byte >= 32 && byte <= 126) {
      currentString += String.fromCharCode(byte);
    } else if (currentString.length >= 3) {
      // 如果当前字符串至少有3个字符，则认为是有效字符串
      strings.push(currentString);
      currentString = '';
    } else {
      currentString = '';
    }
  }
  
  // 添加最后一个字符串
  if (currentString.length >= 3) {
    strings.push(currentString);
  }
  
  return strings;
}

/**
 * 从对象中提取cookie数据
 * @param {Object|string} item - 可能包含cookie数据的对象
 * @param {string} key - 对象的键名
 * @returns {Object} - cookie对象
 */
function extractCookieFromObject(item, key) {
  if (typeof item === 'string') {
    return {
      name: key,
      value: item,
      domain: '',
      path: '/'
    };
  }
  
  return {
    name: item.name || key,
    value: item.value || item.token || item.session || item.credential || '',
    domain: item.domain || item.host || '',
    path: item.path || '/',
    expires: item.expires || item.expirationDate || 0,
    secure: Boolean(item.secure),
    httpOnly: Boolean(item.httpOnly),
    sameSite: item.sameSite || 'Lax'
  };
}

/**
 * 判断字符串是否可能是有效的cookie名称
 * @param {string} str - 要检查的字符串
 * @returns {boolean} - 是否可能是cookie名称
 */
function isValidCookieName(str) {
  if (!str || typeof str !== 'string') return false;
  
  // cookie名称通常的特征
  // 1. 不会太长
  if (str.length > 100) return false;
  
  // 2. 不应包含特殊字符
  if (/[^\w\-.]/.test(str)) return false;
  
  // 3. 常见的cookie命名模式
  const commonPatterns = [
    /^sess(ion)?/i,
    /token/i,
    /auth/i,
    /^id$/i,
    /uid/i,
    /user/i,
    /log(in|ged)/i,
    /^c_\w+/,
    /^JSESSION/i,
    /^ASP\.NET/i,
    /^PHPSESS/i,
    /^wp_/i,
    /^wordpress_/i,
    /^_ga/i,
    /^_gid/i,
    /^_fbp/i,
    /^_pk_/i,
    /^api_/i,
    /^sid$/i,
    /^cookie_/i,
    /^CSRF/i,
    /^xsrf/i,
    /^remember_/i,
    /^_twitter_/i,
    /^_github_/i,
    /^AWSALB/i,
    /^AWSALBCors/i,
    /^(x-)?access-?token/i
  ];
  
  // 如果匹配任何一个常见模式，认为是有效的cookie名称
  for (const pattern of commonPatterns) {
    if (pattern.test(str)) return true;
  }
  
  // 其他可能的cookie名称
  return true;
}

module.exports = {
  findCookieFiles,
  readCookieFile
}; 